<!DOCTYPE html>
<html>
  <head>
    <title>
      Test Multiple Calls to getFloatFrequencyData
    </title>
    <script src="../../resources/testharness.js"></script>
    <script src="../../resources/testharnessreport.js"></script>
    <script src="../resources/audit-util.js"></script>
    <script src="../resources/audit.js"></script>
  </head>
  <body>
    <script id="layout-test-code">
      let sampleRate = 48000;
      // Render enough data to run the test.
      let renderFrames = 2 * 1024;
      let renderDuration = renderFrames / sampleRate;

      let audit = Audit.createTaskRunner();

      audit.define('test', (task, should) => {

        let context = new OfflineAudioContext(1, renderFrames, sampleRate);

        // Use sawtooth oscillator as the source because it has quite a bit of
        // harmonic content. Otherwise, the type doesn't really matter.
        let osc = context.createOscillator();
        osc.type = 'sawtooth';

        // Create an analyser with 256-point FFT.  The FFT size doesn't really
        // matter much.
        let analyser = context.createAnalyser();
        analyser.fftSize = 256;

        osc.connect(analyser);
        analyser.connect(context.destination);

        let success = true;

        // Suspend after getting a full analyser frame. (Not really necessary,
        // but it's nice that the frame doesn't include any initial zeroes.
        let suspendFrame = analyser.fftSize;
        context.suspend(suspendFrame / sampleRate)
            .then(function() {
              // Test successive calls to getFloatFrequencyData in the same
              // rendering quantum.
              let f1 = new Float32Array(analyser.frequencyBinCount);
              let f2 = new Float32Array(analyser.frequencyBinCount);

              analyser.getFloatFrequencyData(f1);
              analyser.getFloatFrequencyData(f2);
              should(f2, 'Second call to getFloatFrequencyData')
                  .beEqualToArray(f1);
            })
            .then(context.resume.bind(context));

        suspendFrame += 128;
        context.suspend(suspendFrame / sampleRate)
            .then(function() {
              // Test successive calls to getByteFrequencyData in the same
              // rendering quantum.
              let f1 = new Uint8Array(analyser.frequencyBinCount);
              let f2 = new Uint8Array(analyser.frequencyBinCount);

              analyser.getByteFrequencyData(f1);
              analyser.getByteFrequencyData(f2);

              should(f2, 'Second call to getByteFrequencyData')
                  .beEqualToArray(f1);
            })
            .then(context.resume.bind(context));

        suspendFrame += 128;
        context.suspend(suspendFrame / sampleRate)
            .then(function() {
              // Test calls to getFloatFrequencyData followed by
              // getByteFrequencyData.  The float data, when converted to byte
              // values should be identical to the result from
              // getByteFrequencyData.
              let f1 = new Float32Array(analyser.frequencyBinCount);
              let f2 = new Uint8Array(analyser.frequencyBinCount);

              analyser.getFloatFrequencyData(f1);
              analyser.getByteFrequencyData(f2);

              let byteValuesFromFloat = convertFloatToByte(
                  f1, analyser.minDecibels, analyser.maxDecibels);
              should(
                  byteValuesFromFloat,
                  'Output of getByteFrequencyData after getFloatFrequencyData')
                  .beEqualToArray(f2);
            })
            .then(context.resume.bind(context));

        suspendFrame += 128;
        context.suspend(suspendFrame / sampleRate)
            .then(function() {
              // Test calls to getByteFrequencyData followed by
              // getFloatFrequencyData.  The float data, when converted to byte
              // values should be identical to the result from
              // getByteFrequencyData.
              let f1 = new Uint8Array(analyser.frequencyBinCount);
              let f2 = new Float32Array(analyser.frequencyBinCount);

              analyser.getByteFrequencyData(f1);
              analyser.getFloatFrequencyData(f2);

              let byteValuesFromFloat = convertFloatToByte(
                  f2, analyser.minDecibels, analyser.maxDecibels);
              should(
                  f1,
                  'Output of getFloatFrequenycData (converted to byte) after getByteFrequencyData')
                  .beEqualToArray(byteValuesFromFloat);
            })
            .then(context.resume.bind(context));

        osc.start();
        context.startRendering().then(() => task.done());
      });

      audit.run();

      // Convert the float frequency data (in dB), |floatFreqData|, to byte
      // values using the dB limits |minDecibels| and |maxDecibels|.  The new
      // byte array is returned.
      function convertFloatToByte(floatFreqData, minDecibels, maxDecibels) {
        let scale = 255 / (maxDecibels - minDecibels);

        return floatFreqData.map(function(x) {
          let value = Math.floor(scale * (x - minDecibels));
          return Math.min(255, Math.max(0, value));
        });
      }
    </script>
  </body>
</html>
